<?php

namespace App\Http\Controllers\Manage;

use App\Http\Controllers\ApiController;
use App\Http\Requests\PatientBaseInfoRequest;
use App\Http\Requests\PatientUpdateRequest;
use App\Http\Requests\SubsequentCreateRequest;
use App\Models\Dynamic\SamWear;
use App\Models\FamilyHistory;
use App\Models\Hospital;
use App\Models\MarriageHistory;
use App\Models\MedicalAuxiliary;
use App\Models\MedicalComplaint;
use App\Models\MedicalDiagnose;
use App\Models\MedicalDispose;
use App\Models\MedicalFollowUp;
use App\Models\MedicalHpi;
use App\Models\MedicalPhysical;
use App\Models\MedicalRecord;
use App\Models\PastHistory;
use App\Models\Patient;
use App\Models\PersonalHistory;
use App\Models\SceneManage;
use App\Models\StMedicalNumber;
use App\Models\UserBase;
use App\Project\Traits\SearchAble;
use App\Transformers\RecordTransformer;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use App\LogicService\Contracts\HospitalManageLogicContract;
use Illuminate\Support\Facades\DB;

/**
 * 病历控制器
 * Class RecordController
 * @package App\Http\Controllers\Manage
 */
class RecordController extends ApiController
{
    use SearchAble;

    protected $hospitalManage;
    public $stUserModel;
    public $stHospitalModel;
    public $stWearModel;
    public $stMedicalNumberModel;


    public function __construct(HospitalManageLogicContract $hospitalManage)
    {
        parent::__construct();
        $this->hospitalManage = $hospitalManage;
        $this->stUserModel = new UserBase();
        $this->stHospitalModel = new Hospital();
        $this->stWearModel = new SamWear();
        $this->stMedicalNumberModel = new StMedicalNumber();
    }

    protected $modelAlias = [
        'first' => [
            'complaint' => MedicalComplaint::class,
            'hpi' => MedicalHpi::class,
            'past' => PastHistory::class,
            'person' => PersonalHistory::class,
            'marriage' => MarriageHistory::class,
            'family' => FamilyHistory::class,
            'physical' => MedicalPhysical::class,
            'auxiliary' => MedicalAuxiliary::class,
            'diagnose' => MedicalDiagnose::class,
            'dispose' => MedicalDispose::class,
        ],

        'follow' => [
            'follow' => MedicalFollowUp::class,
            'physical' => MedicalPhysical::class,
            'auxiliary' => MedicalAuxiliary::class,
            'diagnose' => MedicalDiagnose::class,
            'dispose' => MedicalDispose::class,
        ]
    ];

    protected $searchQueryMap = [// 搜索条件
        'name' => ['field' => 'tn_user_base.name', 'operator' => 'like'],// 患者姓名
        'phone' => ['field' => 'tn_user_base.phone', 'operator' => '='],// 电话
        'hospital_id' => ['field' => 'st_medical_records.hospital_id', 'operator' => '='],// 医院
        'doctor_id' => ['field' => 'st_medical_records.doctor_id', 'operator' => '='],// 医生
        'diabetes_stage' => ['field' => 'tn_user_base.diabetes_stage', 'operator' => '='],// 糖尿病-阶段
//        'medical_number' => ['field' => 'tn_user_base.medical_number', 'operator' => '='],// 病案号
        'clinic_at' => ['field' => 'st_medical_records.clinic_at', 'operator' => '='],// 就诊日期
    ];

    /**
     * 病历列表
     * @param \Illuminate\Http\Request $request
     * @param \App\Models\Patient $patient
     * @return \Illuminate\Http\JsonResponse
     */
    public function index(Request $request, Patient $patient)
    {
        $this->validationOfSearch($request);// 验证搜索参数

        $size = $request->input('size', 15);// 每页个数
        $page = $request->input('page', 1);// 第几页

        $where = $this->parseSearchQueryToWhere($request->all());// query -> where
        $user = \Auth::user();
        $userType = $this->stHospitalModel->getTypeByHospitalId(
            $this->stUserModel->getHospitalIdByUserId($user->id)//获取的是当前用户的医院的id
        );//获取的是当前用户所属的医院的类型
        $type = 1;
        $hospital_ids[] = $user->hospital_id;
        if ($user->isAdmin()) {
            $where[] = ['st_medical_records.is_western', '=', $userType === 1 ? 1 : 0];
        } elseif ($user->isDoctorsAdmin() || $user->isRegionAdmin()) {
            // type=4:医院管理员和区域管理员
            $type = 4;
            $hospitalManage = $this->hospitalManage->show($user->account);// 账号 -> 管理医院
            $hospital_ids = json_decode($hospitalManage->hospital_ids);  //获取自己管辖的医院的id Array
            $hospital_ids[] = $user->hospital_id;  //把自己医院的id再存进去
        } else {
            // type=1:患者和医生只能看自己医院和自己的(这里其实只有医生一个人，没有患者登陆后台)
            $where[] = ['st_medical_records.hospital_id', '=', $user->hospital_id];
            $where[] = ['st_medical_records.doctor_id', '=', $user->id];
        }
        /*如果有病案号的话则在病案号医院的区间查询*/
        $medical_number = $request->input('medical_number');
        if($medical_number){
            $medical_number_ids = StMedicalNumber::where('medical_number',$medical_number)->get()->toArray();
            $userBase_medical_ids = UserBase::where('medical_number',$medical_number)->get()->toArray();
            $userBase_medical_ids = array_column($userBase_medical_ids,'medical_number');
            $medical_number_ids = array_column($medical_number_ids,'patient_id');
            $medical_number_ids = array_unique($medical_number_ids + $userBase_medical_ids);
            if($medical_number_ids){
                $where[] = ['in'=>['tn_user_base.id'=>$medical_number_ids]];
            }else{
                /*如果病案号没有查询出对应的病人的id那么直接返回空*/
                return $this->hasNoData();
            }
        }
        $patients = $patient->paging($size, $page, $where, $type, $hospital_ids, $request->input('wear'));

        $collection = $patients->getCollection();

        /* 动态设备 start */
        $patientIds = $collection->pluck('id')->toArray();

        $wearRes = [];
        if (!empty($patientIds)) {
            $sql = "select max(id) as max_id, userid from `tn_sam_wear` where userid in("
                . implode(',', $patientIds)
                . ") group by userid";
            $sqlRes = DB::select($sql);
            $sqlRes = array_map(function ($value) {
                return (array)$value;
            }, $sqlRes);
            $ids = array_column($sqlRes, 'max_id');
            $wearRes = $this->stWearModel->select('*')
                ->whereIn('id', $ids)->get()->toArray();

        }
        /* 动态设备 end */

        /* 病案号 start */
        $medicalNums = $this->stMedicalNumberModel->getAll(
            ['patient_id', 'hospital_id', 'medical_number'],
            ['in' => ['patient_id' => $patientIds]]
        );

        $finalMedicalNums = [];
        foreach ($medicalNums as $medicalNum) {
            $finalMedicalNums[$medicalNum['patient_id']][] = $medicalNum;
        }
        foreach ($finalMedicalNums as $k => &$v) {
            $v = array_combine(
                array_column($v, 'hospital_id'),
                $v
            );
        }
        $medicalNums = $finalMedicalNums;
        /* 病案号 end */

        $records = MedicalRecord::whereIn('patient_id', $patientIds)
            ->where('is_del', 0)
            ->where('hospital_id','>',0)
            ->withOutGlobalScope('hasBindDoctor')
            ->select(['id', 'patient_id', 'clinic_at', 'visit_type', 'hospital_id'])
            ->orderBy('clinic_at', 'desc')
            ->orderBy('id', 'desc')
            ->get()->groupBy('patient_id');

        $collection->map(function (Patient $patient) use ($records, $wearRes, $medicalNums) {
            $user = \Auth::user();
            $patient->wear_status = -1;//佩戴状态:0-开始,1-结束,-1不是动态用户
            $patient->auth = $user->hospital->type;
            if (!empty($wearRes)) {
                foreach ($wearRes as $item) {
                    if ($item['userid'] == $patient->id) {
                        $patient->wear_status = $item['status'];
                    }
                }
            }
            $patient_records = $records[$patient->id];
            $hospital_ids = [];

            foreach ($patient_records as $key => &$value) {
                $hospital_ids[] = $value->hospital_id;
            }
            if ($user->type == 1) {
                $hospital_ids = [$user->hospital_id];
            }
            $hospitals = Hospital::whereIn('id', $hospital_ids)->select('id as hospital_id', 'name')->get();
            $patient->hospitals = $hospitals;
            $patient->records = $patient_records;
            $patient->medical_number = empty($medicalNums[$patient->id]) ? [] : $medicalNums[$patient->id];
            $patient->first_visit = $patient->records->last()->clinic_at;
            return $patient;
        });
        //=======
        $hospitalsAllPatientsId = $patient->pagingAll($where, $type, $hospital_ids, $request->input('wear'))
            ->getCollection()
            ->pluck('id')
            ->toArray();

        $records_count = MedicalRecord::whereIn('patient_id', $hospitalsAllPatientsId)
            ->where('is_del', 0)
            ->where('hospital_id','>',0)
            ->withOutGlobalScope('hasBindDoctor')
            ->count();
        //=======


        return $this->paginate($patients->setCollection($collection), function (Patient $patient) {
            return $patient->toArray();
        }, [], $records_count);
    }

    public function validationOfSearch(Request $request)
    {
        $this->validate(
            $request,
            [
                'name' => 'alpha_num|max:16',
                'phone' => 'regex:/^1[345789]\d{9}$/',
                'medical_number' => 'string|max:20',
                'clinic_at' => 'date',
            ], [
            'name.alpha' => '患者名称 只能包含汉字、字母、数字。',
            'name.max' => '患者名称 最大 :max个字符。',
            'phone.regex' => '手机号码 格式错误。',
            'medical_number.max' => '病案号 不能超过20个字符。',
            'clinic_at.date' => '就诊日期 必须是一个日期值'
        ]);
    }

    /**
     * 获取病人病历的id 列表 包含首诊(复诊)文本，就诊日期
     */
    public function patient($patient_id)
    {
        $records = MedicalRecord::select(['id', 'clinic_at', 'visit_type'])
            ->where('patient_id', $patient_id)->get();

        return $records;
    }


    public function delete(Request $request)
    {

        $this->validate($request, [
            'record_id' => 'required|integer',
        ]);

        $user_id = \Auth::user()->id;

        $admin_ids = config('admin.admin_ids');

        if (!in_array($user_id, $admin_ids)) {
            return $this->setMessage('请确认管理员身份是否可以删除病例')->setCode(40300)->hasNoData();
        }
        $record_id = $request->input('record_id');

        $records = MedicalRecord::select(['id', 'patient_id', 'hospital_id', 'clinic_at', 'visit_type', 'is_del'])->find($record_id);

        if ($records->visit_type['key'] == 1) {
            $repeat_record = MedicalRecord::where([['patient_id', '=', $records->patient_id],['hospital_id', '=', $records->hospital_id], ['visit_type', '=', 0], ['is_del', '=', 0]])->first();

            if ($repeat_record) {
                return $this->setMessage('请先删除用户本医院复诊病例后删除首诊')->setCode(40300)->hasNoData();
            }
        }
        $records->is_del = 1;
        $records->save();

        return $this->responseForUpdate(true);
    }


    public function isOneFirst(Request $request)
    {

        $this->validate($request, [
            'phone' => 'required|string',
            'hospital_id' => 'required|integer',
        ]);


        $phone = $request->input('phone');

        $user_base = UserBase::where([['phone', '=', $phone], ['type', '=', 1]])->first();

        if (!$user_base) {
            return $this->setMessage('可以修改')->setCode('10000')->response();
        }
        $hospital_id = $request->input('hospital_id');
        $records = MedicalRecord::select(['id', 'clinic_at', 'visit_type', 'is_del'])
            ->where([['hospital_id', '=', $hospital_id], ['patient_id', '=', $user_base->id], ['visit_type', '=', 0], ['is_del', '=', 0]])
            ->first();

        if ($records) {
            return $this->setMessage('该患者已有首诊，请添加复诊')->setCode(40300)->hasNoData();
        }


        return $this->setMessage('可以修改')->setCode('10000')->response();
    }


    /**
     * 基本信息提交
     * @param \App\Http\Requests\PatientBaseInfoRequest $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function store(PatientBaseInfoRequest $request)
    {
        $input = $request->all();

        // 病例只有中医和西医。没有中西医。
        if (1 == $request->user()->hospital->type) {
            $input['is_western'] = 1;
        } else {
            $input['is_western'] = 0;
        }

        \DB::beginTransaction();// 开启事务处理

        try {
            //  存储
            $patient = new Patient();

            $patient = $patient->firstOrNew(['phone' => $input['phone']]);

            if (empty($patient->password)) {
                // 患者未md5前
                $input['password'] = '1016171161711616017161016';
                $input['account'] = time() . rand(100, 999);
            }

            $patient->fill($input)->save();// (1/3).user_base表

            $input['patient_id'] = $patient->id;
            $input['visit_type'] = 1;// 病例类型1：西医首诊（字段已废弃？）

            $record = MedicalRecord::create($input);

            // 病案号 (3/3).record表
            if($input['medical_number']){
                $isMedicalNumExit = $this->stMedicalNumberModel->isMedicalNumExit($input['medical_number']);
                if ($isMedicalNumExit) {
                    return response(['code' => -30001, 'message' => '病案号 已经存在。', 'data' => []]);
                }
            }

            $this->stMedicalNumberModel->insert_db([
                'hospital_id' => $input['hospital_id'],
                'patient_id' => $patient->id,
                'medical_number' => $input['medical_number'],
            ]);

            \DB::commit();
        } catch (\Exception $e) {

            \DB::rollBack();
            throw $e;
        }


        return $this->response(['record_id' => $record->id, 'patient_id' => $patient->id]);
    }

    /**
     * 获取病历信息
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function edit(Request $request)
    {
        $this->editValidate($request);

        return $this->item(
            MedicalRecord::withoutGlobalScope('hasBindDoctor')->findOrFail($request->get('record_id')),
            new RecordTransformer()
        );
    }

    /**
     * 患者信息及病历修改
     * @param \App\Http\Requests\PatientUpdateRequest $request
     * @param \App\Models\Patient $patient
     * @param \App\Models\MedicalRecord $record
     * @return \Illuminate\Http\JsonResponse
     * @throws \Exception
     */
    public function update(PatientUpdateRequest $request, Patient $patient, MedicalRecord $record)
    {
        $patient_id = $request->input('patient_id');
        $hospital_id = $request->input('hospital_id');
        $medical_number = $request->input('medical_number');
        $input = $request->except(['record_id', 'patient_id', 'medical_number','doctor_id','hospital_id']);// 排除
        $record_id = $request->input('record_id');
        $patient_id = $request->input('patient_id');

        \DB::beginTransaction();    //  开启事务处理

        try {
            //  存储
            $patient = $patient->getWithCache($patient_id);
            $record = $record->getWithCache($record_id);

            if (
                !empty($input['doctor_id'])
                && ($input['doctor_id'] != $record->doctor_id)
                && \Auth::user()->isDoctor()
            ) {
                return $this->setMessage('不能修改患者的医生。')->response();
            }

            $patient->fill($input)->save();
            $record->fill($input)->save();
            $oldData = DB::table('st_medical_number')->where(['patient_id'=>$patient_id,'hospital_id'=>$hospital_id])->first();
            $have = DB::table('st_medical_number')->where('medical_number',$medical_number)->first();
            if(!empty($have) && !empty($oldData)){
                if($have->id != $oldData->id && $have->medical_number != ''){
                    return response(['code' => -30001, 'message' => '病案号 已经存在。', 'data' => []]);
                }
            }elseif (empty($have) && empty($oldData)){

                //存在这种情况，证明数据库没有重复的

            }elseif (!empty($have) && empty($oldData)){
                if($have->medical_number != ''){
                    return response(['code' => -30001, 'message' => '病案号 已经存在。', 'data' => []]);
                }

            }elseif(empty($have) && !empty($oldData)){
                //不存在这种情况
            }
            if($oldData){//修改
                $res = DB::table('st_medical_number')->where(['patient_id'=>$patient_id,'hospital_id'=>$hospital_id])->update(['medical_number'=>$medical_number]);
            }else{//添加
                DB::table('st_medical_number')->insert([
                    'hospital_id'=>$hospital_id,
                    'patient_id'=>$patient_id,
                    'medical_number'=>$medical_number,
                    'created_at'=>date('Y-m-d H:i:s',time()),
                    'updated_at'=>date('Y-m-d H:i:s',time()),
                ]);
            }

            \DB::commit();
        } catch (\Exception $e) {

            \DB::rollBack();
            throw $e;
        }

        return $this->responseForUpdate(true);
    }

    /**
     * 复诊创建
     * @param \App\Http\Requests\SubsequentCreateRequest $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function subsequent(SubsequentCreateRequest $request)
    {
        $input = $request->input();
        //添加控制复诊的时间  start  yjq 20190312
        $patient_id = $request->input('patient_id');
        $first_record = MedicalRecord::where('patient_id', $patient_id)->where('visit_type', 1)->first();
        if ($first_record->clinic_at >= $request->input('clinic_at')) {
            return $this->setMessage('复诊时间必须在首诊时间之后')->response();
        }
        //end
        if (1 == $request->user()->hospital->type) {
            $input['is_western'] = 1;
        } else {
            $input['is_western'] = 0;
        }
        $input['visit_type'] = 0;

        $result = MedicalRecord::create($input);

        return $this->response(['id' => $result['id']]);
    }

    /**
     * 检查病历添加了那些项目
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function items(Request $request)
    {
        $this->validateItems($request);

        $record_id = $request->input('record_id');
        $items = explode(',', $request->input('items'));

        $visit = MedicalRecord::withoutGlobalScope('hasBindDoctor')
            ->findOrFail($record_id, ['visit_type'])->isFirstVisit();

        if ($visit) {
            $models = Arr::only($this->modelAlias['first'], $items);
        } else {
            $models = Arr::only($this->modelAlias['follow'], $items);
        }

        $result = [];

        foreach ($models as $key => $model) {
            $result[$key] = (new $model())->where(['record_id' => $record_id])->exists();
        }

        return $this->response($result);
    }

    protected function validateItems(Request $request)
    {
        $this->validate(
            $request,
            [
                'record_id' => 'required|integer|min:1',
                'items' => 'required',
            ], [
            'record_id.required' => '病历ID必须填写',
            'record_id.integer' => '病历ID必须是一个数字',
            'record_id.min' => '病历ID必须大于等于1',
        ]);
    }

    /**
     * @param \Illuminate\Http\Request $request
     */
    public function editValidate(Request $request)
    {
        $this->validate(
            $request,
            [
                'record_id' => 'required|integer|min:1'
            ], [
                'record_id.required' => '病历ID必须填写',
                'record_id.integer' => '病历ID必须是一个数字',
                'record_id.min' => '病历ID必须大于等于1',
            ]
        );
    }


    public function updateColumn(Request $request)
    {
        $input = $request->except(['record_id', 'patient_id']);
        $record_id = $request->input('record_id');
        $patient_id = $request->input('patient_id');

        $record = MedicalRecord::find($record_id);
        $patient = UserBase::find($patient_id);

        $first_record = MedicalRecord::where('patient_id', $patient_id)->where('visit_type', 1)->first();
        if ($first_record->clinic_at >= $request->input('clinic_at')) {
            return $this->setMessage('复诊时间必须在首诊时间之后')->response();
        }
        $user = \Auth::user();

        if ($user->isDoctor() || $user->isRegionAdmin()) {
            unset($input['doctor_id']);
            unset($input['hospital_id']);
        }
        if ($user->isDoctorsAdmin()) {
            unset($input['hospital_id']);
        }

        $record->fill($input)->save();

        if (!$user->isDoctor() && !$user->isRegionAdmin()) {

            $patient->fill($input)->save();
        }

        return $this->responseForUpdate(true);
    }
}